package lianliankan;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import javax.swing.*;

import static jdk.nashorn.internal.runtime.PropertyMap.newMap;

/**
 * @program: LianLianKan
 * @description: Java Lotus
 * @author: spring
 * @create: 2024-08-15
 * 小王总结项目知识点
 * 1。serialVersionUID这个是用来去控制版本的，与序列化和反序列化是有关系的
 * 2。JPanel: Swing 中的一个组件，用于创建面板，以便在图形用户界面中放置其他组件。
 */
public class LianLianKan extends JFrame {

    /**
     * 在 Java 中，serialVersionUID 是一个用于版本控制的唯一标识符，
     * 它与对象的序列化和反序列化过程有关。
     * 序列化是将对象转换为字节流的过程，以便在网络中传输或存储，而反序列化是将字节流转换回对象的过程。
     * static: 表示该字段属于类本身，而不是类的实例
     * 序列化 (Serialization): 将对象的状态保存到文件或其他存储介质，以便后续恢复。
     * 反序列化 (Deserialization): 从保存的字节流中恢复对象的状态。
     * 版本兼容性: 如果类的结构（字段、方法等）发生变化，serialVersionUID 帮助确保反序列化的对象与当前类结构兼容。如果 serialVersionUID 不匹配，Java 将抛出 InvalidClassException 异常。
     * 序列化稳定性: 通过显式声明 serialVersionUID，你可以控制版本的兼容性，避免因为类的改变（例如字段的添加或删除）导致的不兼容问题。
     */
    private static final long serialVersionUID = 1L;


    public LianLianKan() {
        LianLianKanJPanel llk = new LianLianKanJPanel();
        add(llk);
    }

    /**
     * ActionListener: 用于处理动作事件（例如按钮点击）。需要实现 actionPerformed(ActionEvent e) 方法来处理这些事件。
     * ItemListener: 用于处理项事件（例如选择下拉菜单中的项）。需要实现 itemStateChanged(ItemEvent e) 方法来处理这些事件。
     */
    class LianLianKanJPanel extends JPanel implements ActionListener, ItemListener {

        private static final long serialVersionUID = 1L;  //与上面代码的作用一样
        //开始布局连连看的界面
        private int[][] map = new int[8][8];
        private int kind, randomX, randomY, randomX1, randomY1;  //种类
        private int coordinateX, coordinateY, coordinateX1, coordinateY1;//坐标
        private Point lineStart = new Point(0, 0);//坐标移动相应位置
        private int clickTimes;//点击
        private int jishushengyu; //计数剩余
        private int Kinds = 4;
        private int score;
        private int stages; //关卡数

        loudou ld = new loudou();

        JButton BlockButton[][] = new JButton[8][8];
        //ItemSelectable, Accessible在这两个接口中de
        //    public void addItemListener(ItemListener l);类似的方法就可以调用到监听器
        Choice difficultChoice = new Choice();
        //“push”按钮的实现。
        //按钮可以通过操作进行配置，并在一定程度上进行控制。
        // 除了直接配置按钮之外，使用带有按钮的Action还有很多好处。
        JButton newGameButton = new JButton("重新开始");
        JButton reLoad = new JButton("刷新");

        //把背景图和照片依次去使用相对路径放入到里面
        ImageIcon ii = new ImageIcon("src/im/bk.jpg");

        ImageIcon aIcon = new ImageIcon("src/im/1.gif");
        ImageIcon bIcon = new ImageIcon("src/im/2.gif");
        ImageIcon cIcon = new ImageIcon("src/im/3.gif");
        ImageIcon dIcon = new ImageIcon("src/im/4.gif");
        ImageIcon eIcon = new ImageIcon("src/im/5.gif");
        ImageIcon fIcon = new ImageIcon("src/im/6.gif");
        ImageIcon gIcon = new ImageIcon("src/im/7.gif");
        ImageIcon hIcon = new ImageIcon("src/im/8.gif");
        ImageIcon iIcon = new ImageIcon("src/im/9.gif");
        ImageIcon jIcon = new ImageIcon("src/im/10.gif");
        ImageIcon kIcon = new ImageIcon("src/im/11.gif");
        ImageIcon lIcon = new ImageIcon("src/im/12.gif");
        ImageIcon mIcon = new ImageIcon("src/im/13.gif");
        ImageIcon nIcon = new ImageIcon("src/im/14.gif");
        ImageIcon oIcon = new ImageIcon("src/im/15.gif");

        /**
         * Swing的构造函数，创建一个自定义的JPanel，显示游戏画面
         * layout布局管理
         * 创建按钮和监听器
         * 设置背景添加相应的组件到面板
         */
        public LianLianKanJPanel() {

            /**
             *     public void setLayout(LayoutManager mgr) {
             *         layoutMgr = mgr;
             *         invalidateIfValid();
             *     }
             */
            //设置此容器的布局管理器。
            this.setLayout(null);

            //在这里创建了一个新的图形化界面
            //先把网格创建起来
            newMap();
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    BlockButton[i][j] = new JButton();
                    add(BlockButton[i][j]);
                    BlockButton[i][j].addActionListener(this);  //加入监听器
                    BlockButton[i][j].setBounds(30 + j * 40, 30 + i * 40, 31, 34);
                }
            }
            difficultChoice.add("简单");
            difficultChoice.add("中等");
            difficultChoice.add("困难");
            difficultChoice.add("变态");

            //对按钮的设置
            newGameButton.setBounds(map[0].length * 40 + 80, 40, 100, 20);
            newGameButton.setBackground(Color.white);
            newGameButton.setBorderPainted(false);  //去边框

            //对相应填充的设置
            reLoad.setBounds(map[0].length * 40 + 100, 80, 60, 20);
            reLoad.setBackground(Color.white);
            reLoad.setBorderPainted(false);

            //对不同选择的按钮
            difficultChoice.setBounds(map[0].length * 40 + 100, 120, 60, 20);
            difficultChoice.addItemListener(this);
            newGameButton.addActionListener(this);
            reLoad.addActionListener(this);

            this.add(newGameButton);
            this.add(reLoad);
            this.add(difficultChoice);

            //对漏斗进行一个设置
            ld.setBounds(map[0].length * 40 + 100, 200, 70, 150);
            ld.setBackground(Color.black);
            this.add(ld);
        }

        //定义这个漏斗这个类
        class loudou extends JPanel implements Runnable {
            private static final long serialVersionUID = 1L;
            private int dijiguan;
            int remainTimes = 0;
            int x1 = 0;
            int y1 = 30;
            int x2 = 60;
            int y2 = 150;

            //线程
            Thread nThread1;
            //显示图像和文字的图形化界面
            JLabel overJLabel = new JLabel();
            //用于创建对话框窗口的主类。您可以使用这个类来创建自定义对话框，或者调用JOptionPane中的许多类方法来创建各种标准对话框
            JDialog dialog = new JDialog();

            //对这个类中设置了初始化的值
            public loudou() {
                nThread1 = new Thread(this);
                nThread1.start();
                this.setLayout(null);
                this.add(overJLabel);
                overJLabel.setBounds(0, 0, 200, 50);
                overJLabel.setForeground(Color.white);
            }

            //设置第几关
            public void setdijiguan(int x) {
                this.dijiguan = dijiguan;
            }

            //画画函数,重写了原本的这个Java Swing中的组件，在组件上去绘制图形
            public void paintComponent(Graphics g) // 画画函数
            {
                //继承父类中的相关的方法，保证组件的背景被清除了，在其上面进行一个自定义的绘制
                super.paintComponent(g);

                //绘制绿色的线条
                g.setColor(Color.green);  //设置的画笔的颜色为绿色

                //使用for循环绘制56条线条，线条从左到右之间的变短
                for (int i = 0; i < 56; i++) {
                    g.drawLine(x1 + i / 2 + 2, y1 + i, x2 - i / 2 - 2, y1 + i);
                }

                //判断条件
                if (remainTimes < 55) {
                    for (int i = 0; i < remainTimes; i++) {
                        g.drawLine(x1 + i / 2 + 2, y2 - i - 1, x2 - i / 2 - 2, y2 - i
                                - 1);
                    }
                    g.drawLine((x1 + x2) / 2, (y1 + y2) / 2, (x1 + x2) / 2, y2 - 2);
                    g.drawLine((x1 + x2) / 2 + 1, (y1 + y2) / 2 + 1, (x1 + x2) / 2 + 1, y2 - 2);//两条竖线
                    g.setColor(getBackground());
                    for (int i = 0; i < remainTimes; i++) {
                        g.drawLine(x1 + i / 2 + 2, y1 + i, x2 - i / 2 - 2, y1 + i);//覆盖上边的倒三角
                    }
                }

                //显示游戏的状态
                //更新显示剩余的时间
                if (remainTimes >= 50 && remainTimes <= 55)
                    overJLabel.setText(55 - remainTimes + "s");

                //结束游戏
                if (remainTimes == 56)
                    overJLabel.setText("OVER");
            }

            //            设置时间
            public void setTimes(int x) {
                this.remainTimes = x;
            }

            //            获取时间
            public int getTimes() {
                return remainTimes;
            }

            //运行
            public void run() {
                //开始对话框输出
                while (dijiguan < 20) {
                    if (remainTimes == 0) {
                        JOptionPane.showMessageDialog(null, "游戏开始?");
                    }
                    if (remainTimes == 56) {
                        JOptionPane.showMessageDialog(null, "时间到！游戏结束！");
                    }

                    remainTimes++;
                    repaint();

                    try {
                        if (dijiguan < 6)
                            Thread.sleep(1500 - dijiguan * 100);
                        if (dijiguan >= 6 && dijiguan <= 8)
                            Thread.sleep(1000 - (dijiguan - 5) * 50);
                        if (dijiguan > 8)
                            Thread.sleep(850 - (dijiguan - 8) * 20);

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        //再次对这个背景的GUI进行一个美化
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            //是父类JPanel里的方法,会把整个面板用背景色重画一遍,起到清屏的作用

            g.drawImage(ii.getImage(), 0, 0, this);
            //绘制两个文本字符串
            g.setColor(Color.white);
            g.drawString("得分: " + score, 430, 165);
            g.drawString("第 " + (stages + 1) + " 关", 430, 190);

            //利用循环对这个图片进行一个判断
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    switch (map[i][j]) {
                        case 0:

                            BlockButton[i][j].setVisible(false);
                            break;
                        case 1:
                            BlockButton[i][j].setIcon(aIcon);
                            break;
                        case 2:
                            BlockButton[i][j].setIcon(bIcon);
                            break;
                        case 3:
                            BlockButton[i][j].setIcon(cIcon);
                            break;
                        case 4:
                            BlockButton[i][j].setIcon(dIcon);
                            break;
                        case 5:
                            BlockButton[i][j].setIcon(eIcon);
                            break;
                        case 6:
                            BlockButton[i][j].setIcon(fIcon);
                            break;
                        case 7:
                            BlockButton[i][j].setIcon(gIcon);
                            break;
                        case 8:
                            BlockButton[i][j].setIcon(hIcon);
                            break;
                        case 9:
                            BlockButton[i][j].setIcon(iIcon);
                            break;
                        case 10:
                            BlockButton[i][j].setIcon(jIcon);
                            break;
                        case 11:
                            BlockButton[i][j].setIcon(kIcon);
                            break;
                        case 12:
                            BlockButton[i][j].setIcon(lIcon);
                            break;
                        case 13:
                            BlockButton[i][j].setIcon(mIcon);
                            break;
                        case 14:
                            BlockButton[i][j].setIcon(nIcon);
                            break;
                        case 15:
                            BlockButton[i][j].setIcon(oIcon);
                            break;
                        default:
                            break;
                    }

                }

            }

        }

        //重载,在游戏的图形化界面使用，用于重新去初始化并且重新去绘制一个8*8的游戏网格
        public void chongzai() {
            //清除剩余的计数
            jishushengyu = 0;
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    //map中大于0的数量，表示网格中的活跃的元素的个数
                    if (map[i][j] > 0) {
                        jishushengyu++;
                    }
                }
            }
            //创建一个二维数组
            //将map指向了一个新的数组，实际上就是清空了之前的map
            int[][] map1 = new int[8][8];
            this.map = map1;
            //生成随机数
            Random random = new Random();

            for (int i = 0; i < jishushengyu / 2; i++) {
                kind = random.nextInt(Kinds) + 1;  //生成从1到Kinds的随机整数
                //do while 去随机生成位置去放入
                do {
                    randomX1 = random.nextInt(8);
                    randomY1 = random.nextInt(8);
                } while (map[randomY1][randomX1] > 0);

                map[randomY1][randomX1] = kind;

                do {
                    randomX = random.nextInt(8);
                    randomY = random.nextInt(8);
                } while (map[randomY][randomX] > 0);

                map[randomY][randomX] = kind;
            }

            repaint();
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    //设置按钮可见
                    BlockButton[i][j].setVisible(true);
                }
            }
        }

        //开启新的一把游戏
        public void newGame() {
            //在那个前面弹出的对话框中你点击了那个开始游戏的按钮
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    //显示按钮
                    BlockButton[i][j].setEnabled(true);
                    BlockButton[i][j].setVisible(true);
                }
            }
            int[][] map = new int[8][8];
            this.map = map;
            newMap();
            ld.setTimes(0);
            score = 0;
            stages = 0;
            ld.setdijiguan(stages);
        }

        //过关
        public void guoguan() {
            int jishushengyu2 = 0;
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    if (map[i][j] > 0) {
                        jishushengyu2++;
                    }
                }
            }
            if (jishushengyu2 == 0) {
                for (int i = 0; i < 8; i++) {
                    for (int j = 0; j < 8; j++) {
                        BlockButton[i][j].setEnabled(true);
                        BlockButton[i][j].setVisible(true);
                    }
                }
                int[][] map = new int[8][8];
                this.map = map;
                newMap();

                ld.setTimes(0);
                stages++;
                ld.setdijiguan(stages);
                reLoad.setEnabled(true);
            }
        }

        //定义一个newMap的方法，用于去生成这个新的网格
        public void newMap() {
            //初始化这个数字列表，创建一个ArrayList存储整数
            ArrayList<Integer> numbers = new ArrayList<>();//数组链表
            //遍历Kinds次，将每个这个i+1加入这个列表两次，这确保了每种类型的元素至少的出现了两次，保证了初始化布局包含的所有的Kinds类型的元素
            for (int i = 0; i < Kinds; i++) {
                numbers.add(i + 1);//添加到链表的尾部
                numbers.add(i + 1);
            }//每一次去重新布局的时候，都要去保证这个一定有前几种难度的图片类型

            //随机添加元素
            Random random = new Random();
            int temp = 0;
            //最终64个元素
            for (int i = 0; i < 32 - Kinds; i++) {
                temp = random.nextInt(Kinds);
                numbers.add(temp);
                numbers.add(temp);
            }
            //随机打乱元素
            /**
             *     public static void shuffle(List<?> list) {  //存储以列表的方式
             *         Random rnd = r;
             *         if (rnd == null)  //随机元素
             *             r = rnd = new Random(); // harmless race.
             *         shuffle(list, rnd);
             *     }
             */
            Collections.shuffle(numbers);
            map = new int[8][8];
            temp = 0;

            //填充网格
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    map[i][j] = numbers.get(temp++).intValue();
                }
            }
        }

        //响应difficultChoice组件（下拉列表或者是选择框）选择不同的难度
        public void itemStateChanged(ItemEvent e) {
            // TODO 自动生成的方法存根
            if (e.getSource() == difficultChoice) {
                String selected = difficultChoice.getSelectedItem();
                if (selected.equals("简单")) {
                    Kinds = 4;
                    newGame();
                    repaint();
                } else if (selected.equals("中等")) {
                    Kinds = 8;
                    newGame();
                    repaint();
                } else if (selected.equals("困难")) {
                    Kinds = 12;
                    newGame();
                    repaint();
                } else if (selected.equals("变态")) {
                    Kinds = 15;
                }

                //开始新的游戏，并且刷新界面
                newGame();
                repaint();
            }
        }

        //ActionEvent处理这个响应用户的按钮的点击操作
        public void actionPerformed(ActionEvent e) {
            // TODO 自动生成的方法存根

//            如果点击次数大于56，禁用所有的按钮
            if (ld.getTimes() > 56) {
                for (int i = 0; i < 8; i++) {
                    for (int j = 0; j < 8; j++) {
                        BlockButton[j][i].setEnabled(false);
                    }
                }
            }

            //点击了reLoad之后就重载，并且禁用这个按钮
            if (e.getSource() == reLoad) {
                chongzai();
                reLoad.setEnabled(false);
            }

            //点击了新游戏，调用这个newGame方法并且启用这个原本的reLoad的按钮
            if (e.getSource() == newGameButton) {
                newGame();
                reLoad.setEnabled(true);
            }

            //检查点击的按钮并且处理点击事件
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    if (e.getSource() == BlockButton[j][i]) {
                        clickTimes++; // 点击的次数
                        /**
                         * lineStart.move(i, j); 可能是调用了 lineStart 对象的 move 方法，
                         * 将传入的 i 和 j 坐标用于更新或移动某个图形或对象的位置。
                         * 具体来说，lineStart 可能表示一个游戏中的线条、光标或某个可移动的元素，
                         * 而 move(i, j) 方法则负责处理这个元素的位置变动。
                         */
                        lineStart.move(i, j);
                        if (clickTimes % 2 == 1) {
                            coordinateX1 = i;
                            coordinateY1 = j;
                            BlockButton[coordinateY1][coordinateX1].setEnabled(false);
                            BlockButton[coordinateY][coordinateX].setEnabled(true);

                            //	BlockButton[j][i].setEnabled(false);
                        }
                        if (clickTimes % 2 == 0) {

                            coordinateX = i;
                            coordinateY = j;
                            BlockButton[coordinateY][coordinateX].setEnabled(false);
                            BlockButton[coordinateY1][coordinateX1].setEnabled(true);
                        }
                    }

                }
            }

            this.requestFocus();
            clearBlock();

            /*
             * for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) {
             * BlockButton[j][i].setEnabled(true); }
             *
             * }
             */

            repaint();

        }

        //接下里是具体判断的方法
        // --------------------------------------------------------------------------
        // 判断在一列之内两图片之间是否全部是空白或直接相邻
        private boolean containsAllOrNoneZeroInColumn(int posX1, int posY1,
                                                      int posX2, int posY2) {
            // 直接相连,因而不包含空白
            if (Math.abs(posY1 - posY2) == 0) {
                return true;
            }
            int a = posY1 < posY2 ? posY1 : posY2;
            int b = posY1 < posY2 ? posY2 : posY1;//y值:a小 b大
            for (int j = a + 1; j < b; j++) {
                if (map[posX1][j] != 0) {
                    return false;
                }
            }
            return true;
        }

        // 判断在一行之内两图片之间是否全部是空白或直接相邻
        private boolean containsAllOrNoneZeroInRow(int posX1, int posY1,
                                                   int posX2, int posY2) {
            // 直接相连,因而不包含空白
            if (Math.abs(posX1 - posX2) == 0) {
                return true;
            }
            int a = posX1 < posX2 ? posX1 : posX2;
            int b = posX1 < posX2 ? posX2 : posX1;
            for (int i = a + 1; i < b; i++) {
                if (map[i][posY1] != 0) {
                    return false;
                }
            }
            return true;
        }

        // 是否可以一直线相连
        private boolean isLinkByOneLine(int posX1, int posY1, int posX2,
                                        int posY2) {

            if (posX1 != posX2 && posY1 != posY2) {
                return false;
            }
            if (posX1 == posX2) {
                if (containsAllOrNoneZeroInColumn(posX1, posY1, posX2, posY2)) {
                    return true;
                }
            }
            if (posY1 == posY2) {
                if (containsAllOrNoneZeroInRow(posX1, posY1, posX2, posY2)) {
                    return true;
                }
            }
            return false;
        }

        // 是否可以两直线相连
        private boolean isLinkByTwoLines(int posX1, int posY1, int posX2,
                                         int posY2) {
            if (posX1 != posX2 && posY1 != posY2) {
                // x1,y1 to x2,y1 to x2,y2
                if (containsAllOrNoneZeroInRow(posX1, posY1, posX2, posY1)
                        && map[posX2][posY1] == 0
                        && containsAllOrNoneZeroInColumn(posX2, posY1, posX2,
                        posY2)) {
                    return true;
                }
                // x1,y1 to x1,y2 to x2,y2
                if (containsAllOrNoneZeroInColumn(posX1, posY1, posX1, posY2)
                        && map[posX1][posY2] == 0
                        && containsAllOrNoneZeroInRow(posX1, posY2, posX2,
                        posY2)) {
                    return true;
                }

            }
            return false;
        }

        // 是否可以三直线相连
        private boolean isLinkByThreeLines(int posX1, int posY1, int posX2,
                                           int posY2) {
            if (isOnSameEdge(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnThreeLinesLikeArc(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnThreeLinesLikeZigzag(posX1, posY1, posX2, posY2)) {
                return true;
            }
            return false;
        }

        // 是否可以三直线相连,似U形
        private boolean isOnThreeLinesLikeArc(int posX1, int posY1, int posX2,
                                              int posY2) {
            if (isOnUpArc(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnDownArc(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnLeftArc(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnRightArc(posX1, posY1, posX2, posY2)) {
                return true;
            }
            return false;
        }

        // ∪
        private boolean isOnUpArc(int posX1, int posY1, int posX2, int posY2) {
            // Y --> 0
            int lessY = posY1 < posY2 ? posY1 : posY2; //找小y
            for (int j = lessY - 1; j >= 0; j--) {
                if (containsAllOrNoneZeroInRow(posX1, j, posX2, j)
                        && containsAllOrNoneZeroInColumn(posX1, posY1, posX1, j)
                        && containsAllOrNoneZeroInColumn(posX2, posY2, posX2, j)
                        && map[posX1][j] == 0 && map[posX2][j] == 0) {
                    return true;
                }
            }

            if (isOnSameEdge(posX1, 0, posX2, 0)
                    && containsAllOrNoneZeroInColumn(posX1, posY1, posX1, 0)
                    && containsAllOrNoneZeroInColumn(posX2, posY2, posX2, 0)
                    && (map[posX1][0] == 0 && map[posX2][0] == 0
                    || map[posX1][0] == 0
                    && map[posX2][0] == map[posX2][posY2] || map[posX1][0] == map[posX1][posY1]
                    && map[posX2][0] == 0)) {
                return true;
            }

            return false;
        }

        // ∩
        private boolean isOnDownArc(int posX1, int posY1, int posX2, int posY2) {
            int moreY = posY1 < posY2 ? posY2 : posY1;
            for (int j = moreY + 1; j <= 8 - 1; j++) {
                if (containsAllOrNoneZeroInRow(posX1, j, posX2, j)
                        && containsAllOrNoneZeroInColumn(posX1, posY1, posX1, j)
                        && containsAllOrNoneZeroInColumn(posX2, posY2, posX2, j)
                        && map[posX1][j] == 0 && map[posX2][j] == 0) {
                    return true;
                }
            }
            if (isOnSameEdge(posX1, 8 - 1, posX2, 8 - 1)
                    && containsAllOrNoneZeroInColumn(posX1, posY1, posX1, 8 - 1)
                    && containsAllOrNoneZeroInColumn(posX2, posY2, posX2, 8 - 1)
                    && (map[posX1][8 - 1] == 0 && map[posX2][8 - 1] == 0
                    || map[posX1][8 - 1] == map[posX1][posY1]
                    && map[posX2][8 - 1] == 0 || map[posX1][8 - 1] == 0
                    && map[posX2][8 - 1] == map[posX2][posY2])) {
                return true;
            }
            return false;
        }

        // ﹚
        private boolean isOnLeftArc(int posX1, int posY1, int posX2, int posY2) {
            int lessX = posX1 < posX2 ? posX1 : posX2;
            for (int i = lessX - 1; i >= 0; i--) {
                if (containsAllOrNoneZeroInColumn(i, posY1, i, posY2)
                        && containsAllOrNoneZeroInRow(i, posY1, posX1, posY1)
                        && containsAllOrNoneZeroInRow(i, posY2, posX2, posY2)
                        && map[i][posY1] == 0 && map[i][posY2] == 0) {
                    return true;
                }
            }

            if (isOnSameEdge(0, posY1, 0, posY2)
                    && containsAllOrNoneZeroInRow(0, posY1, posX1, posY1)
                    && containsAllOrNoneZeroInRow(0, posY2, posX2, posY2)
                    && (map[0][posY1] == 0 && map[0][posY2] == 0
                    || map[0][posY1] == map[posX1][posY1]
                    && map[0][posY2] == 0 || map[0][posY1] == 0
                    && map[0][posY2] == map[posX2][posY2])) {
                return true;
            }

            return false;
        }

        // （
        private boolean isOnRightArc(int posX1, int posY1, int posX2, int posY2) {
            int moreX = posX1 < posX2 ? posX2 : posX1;
            for (int i = moreX + 1; i <= 8 - 1; i++) {
                if (containsAllOrNoneZeroInColumn(i, posY1, i, posY2)
                        && containsAllOrNoneZeroInRow(i, posY1, posX1, posY1)
                        && containsAllOrNoneZeroInRow(i, posY2, posX2, posY2)
                        && map[i][posY1] == 0 && map[i][posY2] == 0) {
                    return true;
                }
            }

            if (isOnSameEdge(8 - 1, posY1, 8 - 1, posY2)
                    && containsAllOrNoneZeroInRow(posX1, posY1, 8 - 1, posY1)
                    && containsAllOrNoneZeroInRow(posX2, posY2, 8 - 1, posY2)
                    && (map[8 - 1][posY1] == 0 && map[8 - 1][posY2] == 0
                    || map[8 - 1][posY1] == map[posX1][posY1]
                    && map[8 - 1][posY2] == 0 || map[8 - 1][posY1] == 0
                    && map[8 - 1][posY2] == map[posX2][posY2])) {
                return true;
            }

            return false;
        }

        // 是否可以三直线相连,似之字形N
        private boolean isOnThreeLinesLikeZigzag(int posX1, int posY1,
                                                 int posX2, int posY2) {
            if (isOnZigzagWith1Row2Cols(posX1, posY1, posX2, posY2)) {
                return true;
            }
            if (isOnZigzagWith2Rows1Col(posX1, posY1, posX2, posY2)) {
                return true;
            }

            return false;
        }

        // 是否可以三直线相连,似之字形, 两行一列 Z
        private boolean isOnZigzagWith2Rows1Col(int posX1, int posY1,
                                                int posX2, int posY2) {
            int moreX = posX1 < posX2 ? posX2 : posX1;
            int lessX = posX1 < posX2 ? posX1 : posX2;
            for (int i = lessX + 1; i < moreX; i++) {
                if (containsAllOrNoneZeroInColumn(i, posY1, i, posY2)
                        && containsAllOrNoneZeroInRow(i, posY1, posX1, posY1)
                        && containsAllOrNoneZeroInRow(i, posY2, posX2, posY2)
                        && map[i][posY1] == 0 && map[i][posY2] == 0) {
                    return true;
                }
            }
            return false;
        }

        // 是否可以三直线相连,似之字形, 一行两列
        private boolean isOnZigzagWith1Row2Cols(int posX1, int posY1,
                                                int posX2, int posY2) {
            int moreY = posY1 < posY2 ? posY2 : posY1;
            int lessY = posY1 < posY2 ? posY1 : posY2;
            for (int j = lessY + 1; j < moreY; j++) {
                if (containsAllOrNoneZeroInRow(posX1, j, posX2, j)
                        && containsAllOrNoneZeroInColumn(posX1, posY1, posX1, j)
                        && containsAllOrNoneZeroInColumn(posX2, posY2, posX2, j)
                        && map[posX1][j] == 0 && map[posX2][j] == 0) {
                    return true;
                }
            }
            return false;
        }

        // 是否处于游戏区域的4条边的同一边上
        private boolean isOnSameEdge(int posX1, int posY1, int posX2, int posY2) {
            if ((posY1 == posY2 && posY2 == 0)
                    || (posY1 == posY2 && posY2 == 8 - 1)
                    || (posX1 == posX2 && posX2 == 0)
                    || (posX1 == posX2 && posX2 == 8 - 1)) {
                return true;
            }

            return false;
        }

        // --------------------------------------------------------------------------
        public boolean ifcanTouch(int posX1, int posY1, int posX2, int posY2) {

            if (isLinkByOneLine(posX1, posY1, posX2, posY2)) {
                return true;
            }
            // 是否可以两直线相连
            if (isLinkByTwoLines(posX1, posY1, posX2, posY2)) {
                return true;
            }
            // 是否可以三直线相连
            if (isLinkByThreeLines(posX1, posY1, posX2, posY2)) {
                return true;
            }

            return false;

        }

        public void clearBlock() {
            if (clickTimes >= 2) {
                if (map[coordinateY1][coordinateX1] == map[coordinateY][coordinateX] && !((coordinateX1 == coordinateX) && (coordinateY1 == coordinateY))) {
                    if (ifcanTouch(coordinateY1, coordinateX1, coordinateY, coordinateX)) {
                        if (map[coordinateY1][coordinateX1] > 0)
                            score += 10;

                        map[coordinateY1][coordinateX1] = 0;
                        map[coordinateY][coordinateX] = 0;
                        guoguan();

                    }
                }
            }
        }


    }

    public static void main(String[] args) {
        String lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";//swing 外观和感觉
        try {
            UIManager.setLookAndFeel(lookAndFeel);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        LianLianKan frame = new LianLianKan();
        frame.setTitle("连连看");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(100, 100, 560, 430);
        frame.setLocation(440, 100);
//		frame.setSize(600, 500);
        frame.setSize(540, 440);
        frame.setVisible(true);
    }
}
